// ==UserScript==
// @name         12306-自动抢票
// @description  解放你的双手
// @author       Lhy
// @include      *://kyfw.12306.cn/otn/leftTicket/init*
// @include      *:https://kyfw.12306.cn/otn/confirmPassenger/initDc*
// @require     https://cdn.staticfile.org/jquery/3.5.1/jquery.min.js
// @grant        GM_addStyle
// @grant       GM.setValue
// @grant       GM.getValue
// @grant       GM.deleteValue
// @run-at       document-start
// ==/UserScript==
let sleep = (ms)=> { return new Promise(resolve => setTimeout(resolve, ms)); }
const allauto = ['wuzuo', 'yingzuo', 'swz','yidengzuo','erdengzuo','ruanwo','yingwo'];
let config = {
    'autodo': allauto,
};
let patterns = [];
let Info=[];
let Path=[];
async function saveStatus() {
    for (let id of allauto) {
        let isChecked = $('#' + id).prop("checked");
        await GM.setValue(id, isChecked); // 保存每个选项的状态
    }

    let token = $('.tokenvalue').val(); // 获取输入的 token
    let startTime = $('#start-time').val(); // 获取用户输入的开始时间
    let endTime = $('#end-time').val(); // 获取用户输入的结束时间

    await GM.setValue('token', token);
    await GM.setValue('startTime', startTime); // 保存开始时间
    await GM.setValue('endTime', endTime); // 保存结束时间

    console.log('状态已保存');
}

   function getTrIndex(element) {
    // 遍历父节点直到找到<tr>标签
    while (element && element.tagName.toLowerCase() !== 'tr') {
        element = element.parentElement;
    }

    if (!element) {
        return null;  // 没有找到<tr>元素
    }

    var ix = 0;
    var siblings = element.parentNode.childNodes;

    // 遍历兄弟节点并找到目标 <tr> 的位置
    for (var i = 0; i < siblings.length; i++) {
        var sibling = siblings[i];
        if (sibling === element) {
            return ix + 1;  // 返回<tr>的位置 (索引从1开始)
        }
        if (sibling.nodeType === 1 && sibling.tagName.toLowerCase() === 'tr') {
            ix++;
        }
    }
    return null;
}

async function restoreStatus() {
    let savedToken = await GM.getValue('token', ''); // 获取保存的 token
    if (savedToken) {
        $('.tokenvalue').val(savedToken); // 设置为输入框的值
    }

    let savedStartTime = await GM.getValue('startTime', ''); // 获取保存的开始时间
    let savedEndTime = await GM.getValue('endTime', ''); // 获取保存的结束时间
    if (savedStartTime) {
        $('#start-time').val(savedStartTime); // 设置为输入框的值
    }
    if (savedEndTime) {
        $('#end-time').val(savedEndTime); // 设置为输入框的值
    }

    for (let id of allauto) {
        let storedValue = await GM.getValue(id, false); // 获取存储的状态，默认为false
        $('#' + id).prop("checked", storedValue); // 恢复每个选项的状态
        // 根据状态恢复patterns
        if (storedValue) {
            switch (id) {
                case 'wuzuo':
                    if (!patterns.some(pattern => pattern.source === '无座')) {
                        patterns.push(/无座/);
                    }
                    break;
                case 'yingzuo':
                    if (!patterns.some(pattern => pattern.source === '硬座')) {
                        patterns.push(/硬座/);
                    }
                    break;
                case 'swz':
                    if (!patterns.some(pattern => pattern.source === '商务座')) {
                        patterns.push(/商务座/);
                    }
                    break;
                case 'yidengzuo':
                    if (!patterns.some(pattern => pattern.source === '一等座')) {
                        patterns.push(/一等座/);
                    }
                    break;
                case 'erdengzuo':
                    if (!patterns.some(pattern => pattern.source === '二等座')) {
                        patterns.push(/二等座/);
                    }
                    break;
                case 'ruanwo':
                    if (!patterns.some(pattern => pattern.source === '软卧')) {
                        patterns.push(/软卧/);
                    }
                    break;
                case 'yingwo':
                    if (!patterns.some(pattern => pattern.source === '硬卧')) {
                        patterns.push(/硬卧/);
                    }
                    break;
            }
        }
    }
}

function getElementsInSameRow(targetElement) {
    // 获取目标元素的父元素（通常是行级元素）
    var parentElement = targetElement.parentNode;

    // 获取目标元素的位置信息
    var targetRect = targetElement.getBoundingClientRect();
    var targetTop = targetRect.top;

    // 存放同一行元素的数组
    var elementsInSameRow = [];

    // 遍历父元素下的所有子元素
    Array.from(parentElement.children).forEach(function(childElement) {
        // 排除目标元素本身
        if (childElement !== targetElement) {
            // 获取子元素的位置信息
            var childRect = childElement.getBoundingClientRect();
            var childTop = childRect.top;

            // 如果子元素与目标元素在同一行（根据top值判断）
            if (childTop === targetTop&&childElement.contains('cds')) {
                elementsInSameRow.push(childElement);
            }
        }
    });

    return elementsInSameRow;
}
function clickElementByXPath(xpath) {
    let element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    if (element) {
        element.click();
    let audio = new Audio('https://www.w3cschool.cn/statics/demosource/horse.mp3');  // Replace with the actual audio file URL

    audio.play().then(() => {
      console.log("Audio started playing once");
    }).catch(error => {
      console.log("Error playing audio: ", error);
    });
        console.log(`点击了元素: ${xpath}`);
    } else {
        console.log(`未找到元素: ${xpath}`);
    }
}

function clickFirstPathElement() {
    if (Path.length > 0) {
        let firstXPath = Path[0]; // 获取 Path 数组中的第一个 XPath
        console.log(firstXPath);
        clickElementByXPath(firstXPath); // 点击第一个 XPath 对应的元素
    } else {
        console.log('Path 数组为空');
    }

}

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id + "header")) {
    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  } else {
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    document.onmouseup = null;
    document.onmousemove = null;
  }
}
function insertTrIndexIntoXPath(xpathTemplate, trIndex) {
    // 将模板中的 'tr[]' 替换为 'tr[数字]'
    return xpathTemplate.replace('tr[]', `tr[${trIndex}]`);
}
function getElementInfoFromXPath(xpath) {
    let element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    if (element) {
        return element.textContent || element.innerText || element.value;  // 返回元素的文本或值
    } else {
        return '元素未找到';
    }
}
function pageFullyLoaded() {
    $(`<style>.course-main{padding-left: 0px ! important;}.yunPanel input[type="checkbox"]{margin-left: 10px;}.yunPanel h3,.yunPanel input,.yunPanel label{font-size:smaller}.yunPanel p{margin:10px 0}.yunPanel{padding:5px 5px;position:absolute;top:10px;right:5px;height:220px;width:200px;border:1px solid #000;background-color:#fcff6680;z-index:9999}.yunPanel .close{position:absolute;cursor:pointer;top:8px;right:10px}.yunPanel .close:hover{color:#00000088}</style>`).appendTo("head");

    $(document.body).after(`
    <div class="yunPanel">
        <h1 style="text-align: center;font-size: medium;">12306-自动抢票</h1>
        <div>
            <div style="text-align:center;font-size:small;">关注微信小程序'虾推啥',车票的信息最终会发送到这个小程序中</div>
            <input style="width:100%" placeholder='输入虾推啥的token' type="text" class='tokenvalue'>
            <input type="checkbox" id="wuzuo">
            <label for="wuzuo">无座</label>
            <input type="checkbox" id="yingzuo">
            <label for="yingzuo">硬座</label>
            <input type="checkbox" id="swz">
            <label for="swz">商务座</label>
            <input type="checkbox" id="yidengzuo" >
            <label for="yidengzuo">一等座</label>
            <input type="checkbox"  id="erdengzuo">
            <label for="erdengzuo">二等座</label>
            <input type="checkbox" id="ruanwo">
            <label for="ruanwo">软卧</label>
            <input type="checkbox" id="yingwo">
            <label for="yingwo">硬卧</label>
        </div>

        <!-- 时间选择器 -->
        <div>
            <label for="start-time">乘车时间范围:</label>
            <input type="time" id="start-time" name="start-time">
            <label for="end-time">~</label>
            <input type="time" id="end-time" name="end-time">
        </div>

        <button id="yun_save" style="float: left;margin-top:5px;width: 48%;">保存</button>
        <button id="yun_start" style="float: right;margin-top:5px;width: 48%;">开始</button>
    </div>
    `);

    restoreStatus(); // 加载时恢复状态

    $('#yun_start').click(() => {
        console.log("开始");
        startTicketSelection(); // 启动抢票流程
    });

    $('#yun_save').click(() => {
        console.log('保存');
        savePatternsAndStatus(); // 保存状态
    });
}
async function startTicketSelection() {
    let startTime = $('#start-time').val(); // 获取用户输入的开始时间
    let endTime = $('#end-time').val(); // 获取用户输入的结束时间

    if (!startTime || !endTime) {
        alert('请填写完整的时间范围');
        return;
    }

    let token = $('.tokenvalue').val(); // 获取输入的token
    console.log(token);

    while (1) {
        let xpathTemplate = '/html/body/div[2]/div[8]/div[12]/table/tbody/tr[]/td[1]/div/div[3]/strong[1]';
        let xpathTemplate2 = '/html/body/div[2]/div[8]/div[12]/table/tbody/tr[]/td[13]/a';
        let elements = document.querySelectorAll('.btn92s');
        elements.forEach(element => { element.dispatchEvent(new Event('click')); });
        await sleep(3000);

        let found = false;

        $('.yes').each((i, item) => {
            let str = item.getAttribute('aria-label');
            let trIndex = getTrIndex(item); // 获取<tr>的索引
            let finalXPath = insertTrIndexIntoXPath(xpathTemplate, trIndex); // 完整 XPath
            let finalXPath2 = insertTrIndexIntoXPath(xpathTemplate2, trIndex); // 点击链接的 XPath

            let elementInfo = getElementInfoFromXPath(finalXPath); // 获取元素信息
            let elementTime = parseTimeFromElementInfo(elementInfo); // 解析时间

            // 判断时间是否在用户选择的范围内
            if (elementTime && isTimeInRange(elementTime, startTime, endTime)) {
                // 判断座位类型是否符合条件
                $.each(patterns, (index, pattern) => {
                    console.log(pattern);
                    if (pattern.test(str)) {
                        Info.push(str);
                        Info.push(elementInfo);
                        Path.push(finalXPath2);
                        Info.push('\n');
                        found = true;
                        return false; // 找到一个符合条件的票后停止循环
                    }
                });
            }
        });

         $('.t-num').each((i, item) => {
            let str = item.getAttribute('aria-label');
            let trIndex = getTrIndex(item); // 获取<tr>的索引
            let finalXPath = insertTrIndexIntoXPath(xpathTemplate, trIndex); // 完整 XPath
            let finalXPath2 = insertTrIndexIntoXPath(xpathTemplate2, trIndex); // 点击链接的 XPath

            let elementInfo = getElementInfoFromXPath(finalXPath); // 获取元素信息
            let elementTime = parseTimeFromElementInfo(elementInfo); // 解析时间

            // 判断时间是否在用户选择的范围内
            if (elementTime && isTimeInRange(elementTime, startTime, endTime)) {
                // 判断座位类型是否符合条件
                $.each(patterns, (index, pattern) => {
                    console.log(pattern);
                    if (pattern.test(str)) {
                        Info.push(str);
                        Info.push(elementInfo);
                        Path.push(finalXPath2);
                        Info.push('\n');
                        found = true;
                        return false; // 找到一个符合条件的票后停止循环
                    }
                });
            }
        });
        if (found || Info.length != 0) {
            break;
        }
    }
    clickFirstPathElement();
    await(3000);
    fetch('https://wx.xtuis.cn/' + encodeURIComponent(token) + '.send' + '?text=车票信息&desp=' + encodeURIComponent(Info[0])+','+encodeURIComponent(Info[1]));
    Info = [];
    Path = [];
}
function savePatternsAndStatus() {
    config.autodo = [];
    $.each(allauto, (index, id) => {
        if ($('#' + id).prop("checked")) {
            // 保存选中的座位类型模式
            switch (id) {
                case 'wuzuo':
                    if (!patterns.some(pattern => pattern.source === '无座')) {
                        patterns.push(/无座/);
                    }
                    break;
                case 'yingzuo':
                    if (!patterns.some(pattern => pattern.source === '硬座')) {
                        patterns.push(/硬座/);
                    }
                    break;
                case 'swz':
                    if (!patterns.some(pattern => pattern.source === '商务座')) {
                        patterns.push(/商务座/);
                    }
                    break;
                case 'yidengzuo':
                    if (!patterns.some(pattern => pattern.source === '一等座')) {
                        patterns.push(/一等座/);
                    }
                    break;
                case 'erdengzuo':
                    if (!patterns.some(pattern => pattern.source === '二等座')) {
                        patterns.push(/二等座/);
                    }
                    break;
                case 'ruanwo':
                    if (!patterns.some(pattern => pattern.source === '软卧')) {
                        patterns.push(/软卧/);
                    }
                    break;
                case 'yingwo':
                    if (!patterns.some(pattern => pattern.source === '硬卧')) {
                        patterns.push(/硬卧/);
                    }
                    break;
            }
        } else {
            // 移除未选中的座位类型模式
            switch (id) {
                case 'wuzuo':
                    patterns = patterns.filter(pattern => pattern.source !== '无座');
                    break;
                case 'yingzuo':
                    patterns = patterns.filter(pattern => pattern.source !== '硬座');
                    break;
                case 'swz':
                    patterns = patterns.filter(pattern => pattern.source !== '商务座');
                    break;
                case 'yidengzuo':
                    patterns = patterns.filter(pattern => pattern.source !== '一等座');
                    break;
                case 'erdengzuo':
                    patterns = patterns.filter(pattern => pattern.source !== '二等座');
                    break;
                case 'ruanwo':
                    patterns = patterns.filter(pattern => pattern.source !== '软卧');
                    break;
                case 'yingwo':
                    patterns = patterns.filter(pattern => pattern.source !== '硬卧');
                    break;
            }
        }
    });
    saveStatus(); // 保存状态
}

// 时间解析函数
function parseTimeFromElementInfo(info) {
    let timeMatch = info.match(/\d{2}:\d{2}/); // 匹配时间格式
    return timeMatch ? timeMatch[0] : null;
}

// 判断时间是否在范围内
function isTimeInRange(time, startTime, endTime) {
    return time >= startTime && time <= endTime;
}

window.addEventListener ("load", pageFullyLoaded);